#include "util/lockguard.hxx"
#include "db/staticindexarray.hxx"
#include "db/indexarraymapping.hxx"

StaticIndexArray::StaticIndexArray(const std::string& partitionPath, uint32_t indexArrayCapacity)
: IndexArray(partitionPath, indexArrayCapacity) {

}


StaticIndexArray::~StaticIndexArray() {

    if(m_indexArrayFile) { delete m_indexArrayFile; m_indexArrayFile = NULL; }
}

DbStatus StaticIndexArray::init() {

    uint32_t sectionSize = 64;
    m_entries = new IndexArrayMapping(m_capacity, sectionSize);
    m_indexArrayFile = new IndexArrayFile(m_partitionPath, m_capacity, sizeof(uint64_t));
    
    return m_indexArrayFile->init();
}

DbStatus StaticIndexArray::get(uint32_t index, uint64_t& value) {

    DbStatus ret;

    if(index >= m_capacity) return DbStatus("StaticIndexArray::get", DbStatus::DB_INDEXARRAYOVERFLOW);
    value = m_indexArrayFile->get(index);

    return ret;
}



DbStatus StaticIndexArray::set(uint32_t index, uint64_t value, uint64_t scn) {

    DbStatus ret;

    if(index >= m_capacity) return DbStatus("StaticIndexArray::get", DbStatus::DB_INDEXARRAYOVERFLOW);

    m_indexArrayFile->set(index, value, scn);
    m_entries->insert(index);
    
    return ret;
}


DbStatus StaticIndexArray::set(uint32_t index, uint64_t value) {
    
    DbStatus ret;

    if(index >= m_capacity) return DbStatus("StaticIndexArray::get", DbStatus::DB_INDEXARRAYOVERFLOW);

    m_indexArrayFile->set(index, value);
    m_entries->insert(index);
    
    return ret;
}



DbStatus StaticIndexArray::flush() {

    DbStatus ret = applyEntries(); if(!ret.isok()) return ret;

    uint64_t lwm, hwm;
    getWaterMarks(lwm, hwm);
    lwm = hwm;
    setWaterMarks(lwm, hwm);

    return m_indexArrayFile->flush();
}

//should be invoke before sync a partition, normally called by datastroe::sync
void StaticIndexArray::switchEntries() {

    LockGuard lock(m_mutex);

    IndexArrayMapping* pv = m_entries;

    uint32_t sectionSize = 64;
    m_entries = new IndexArrayMapping(m_capacity, sectionSize);
    m_entriesNotAppliedYet.push_back(pv);
}

//protected by sync lock
DbStatus StaticIndexArray::applyEntries() {

    DbStatus ret;

    //write hwm first
    ret = m_indexArrayFile->saveHeader();
    if(!ret.isok()) return ret;

    LockGuard lock(m_mutex);

    IndexArrayMapping* entry = NULL;
    if(!m_entriesNotAppliedYet.empty()) entry = m_entriesNotAppliedYet[0];
    for(int i = 1; i < m_entriesNotAppliedYet.size(); ++i) {

        IndexArrayMapping* pv = m_entriesNotAppliedYet[i];
        entry->merge(*pv);
        delete pv;
    }

    if(entry) {

        ret = m_indexArrayFile->applyEntries(*entry);
        delete entry;
        m_entriesNotAppliedYet.clear();
    }


    return ret;
}

